﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.IdentityFramework;
using Abp.Linq.Extensions;
using Castle.MicroKernel.Registration;
using LZ.DCode.Authorization;
using LZ.DCode.Authorization.Roles;
using LZ.DCode.Authorization.Users;
using LZ.DCode.Roles.Dto;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using MyCompanyName.AbpZeroTemplate.Authorization.Permissions;

namespace LZ.DCode.Roles
{
    [AbpAuthorize(PermissionNames.Pages_Roles)]
    public class RoleAppService : AsyncCrudAppService<Role, RoleDto, int, PagedRoleResultRequestDto, CreateRoleDto, RoleDto>, IRoleAppService
    {
        private readonly RoleManager _roleManager;
        private readonly UserManager _userManager;

        public RoleAppService(IRepository<Role> repository, RoleManager roleManager, UserManager userManager)
            : base(repository)
        {
            _roleManager = roleManager;
            _userManager = userManager;
        }

        public override async Task<RoleDto> CreateAsync(CreateRoleDto input)
        {
            CheckCreatePermission();

            var role = ObjectMapper.Map<Role>(input);
            role.SetNormalizedName();

            CheckErrors(await _roleManager.CreateAsync(role));

            var grantedPermissions = PermissionManager
                .GetAllPermissions()
                .Where(p => input.Permissions.Contains(p.Name))
                .ToList();

            await _roleManager.SetGrantedPermissionsAsync(role, grantedPermissions);

            return MapToEntityDto(role);
        }

        public async Task<ListResultDto<RoleListDto>> GetRolesAsync(GetRolesInput input)
        {
            var roles = await _roleManager
                .Roles
                .WhereIf(
                    !input.Permission.IsNullOrWhiteSpace(),
                    r => r.Permissions.Any(rp => rp.Name == input.Permission && rp.IsGranted)
                )
                .ToListAsync();

            return new ListResultDto<RoleListDto>(ObjectMapper.Map<List<RoleListDto>>(roles));
        }

        public override async Task<RoleDto> UpdateAsync(RoleDto input)
        {
            CheckUpdatePermission();

            var role = await _roleManager.GetRoleByIdAsync(input.Id);

            ObjectMapper.Map(input, role);

            CheckErrors(await _roleManager.UpdateAsync(role));

            var grantedPermissions = PermissionManager
                .GetAllPermissions()
                .Where(p => input.Permissions.Contains(p.Name))
                .ToList();

            await _roleManager.SetGrantedPermissionsAsync(role, grantedPermissions);

            return MapToEntityDto(role);
        }

        public override async Task DeleteAsync(EntityDto<int> input)
        {
            CheckDeletePermission();

            var role = await _roleManager.FindByIdAsync(input.Id.ToString());
            var users = await _userManager.GetUsersInRoleAsync(role.NormalizedName);

            foreach (var user in users)
            {
                CheckErrors(await _userManager.RemoveFromRoleAsync(user, role.NormalizedName));
            }

            CheckErrors(await _roleManager.DeleteAsync(role));
        }

        public Task<ListResultDto<PermissionDto>> GetAllPermissions()
        {
            var permissions = PermissionManager.GetAllPermissions();

            return Task.FromResult(new ListResultDto<PermissionDto>(
                ObjectMapper.Map<List<PermissionDto>>(permissions)
            ));
        }

        protected override IQueryable<Role> CreateFilteredQuery(PagedRoleResultRequestDto input)
        {
            return Repository.GetAllIncluding(x => x.Permissions)
                .WhereIf(!input.Keyword.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Keyword)
                || x.DisplayName.Contains(input.Keyword)
                || x.Description.Contains(input.Keyword));
        }

        protected override async Task<Role> GetEntityByIdAsync(int id)
        {
            return await Repository.GetAllIncluding(x => x.Permissions).FirstOrDefaultAsync(x => x.Id == id);
        }

        protected override IQueryable<Role> ApplySorting(IQueryable<Role> query, PagedRoleResultRequestDto input)
        {
            return query.OrderBy(r => r.DisplayName);
        }

        protected virtual void CheckErrors(IdentityResult identityResult)
        {
            identityResult.CheckErrors(LocalizationManager);
        }


        //获取用户 权限id
        public async Task<Dictionary<string, bool>> GetUserRolesAsync()
        {
            List<string> per = new List<string>();
            List<string> getPermission = new List<string>();
            var currentUser = await GetCurrentUserAsync();
            var roles = await _userManager.GetRolesAsync(currentUser);
            if (roles == null)
            {
                throw new Exception("There is no current user!");
            }
            Role role = new Role();
            Dictionary<string, bool> dictionary = new Dictionary<string, bool>();
            var grantedPermissions = new Permission[0];
            for (int i = 0; i < roles.Count; i++)
            {
                role = await _roleManager.GetRoleByNameAsync(roles[i]);
                grantedPermissions = (await _roleManager.GetGrantedPermissionsAsync(role)).ToArray();
                getPermission = grantedPermissions.Select(p => p.Name).ToList();
                for (int p = 0; p < getPermission.Count; p++)
                {
                    if (per.IndexOf(getPermission[p]) < 0)
                    {
                        per.Add(getPermission[p]);
                        dictionary.Add(getPermission[p], true);

                    }
                }
            }
            return dictionary;
        }

        /// <summary>
        /// 获取当前用户
        /// </summary>
        /// <returns></returns>
        protected virtual Task<User> GetCurrentUserAsync()
        {
            var user = _userManager.FindByIdAsync(AbpSession.UserId.Value.ToString());
            if (user == null)
            {
                throw new Exception("There is no current user!");
            }

            return user;
        }

        //  [AbpAuthorize(AppPermissions.Pages_Administration_Roles_Create, AppPermissions.Pages_Administration_Roles_Edit)]
        public async Task<GetRoleForEditOutput> GetRoleForEdit(NullableIdDto input)
        {
            List<RoleNodes> listTreeAll = new List<RoleNodes>();
            RoleNodes treeAll = new RoleNodes();
            var permissions = PermissionManager.GetAllPermissions();
            var grantedPermissions = new Permission[0];
            RoleEditDto roleEditDto;
            if (input.Id.HasValue) //Editing existing role?
            {
                var role = await _roleManager.GetRoleByIdAsync(input.Id.Value);
                grantedPermissions = (await _roleManager.GetGrantedPermissionsAsync(role)).ToArray();
                roleEditDto = ObjectMapper.Map<RoleEditDto>(role);
            }
            else
            {
                roleEditDto = new RoleEditDto();
            }
            List<FlatPermissionDto> fp = ObjectMapper.Map<List<FlatPermissionDto>>(permissions).OrderBy(p => p.DisplayName).ToList();
            for (int i = 0; i < fp.Count; i++)
            {

                if (String.IsNullOrEmpty(fp[i].ParentName))
                {
                    treeAll.Title = fp[i].DisplayName;
                    treeAll.Key = fp[i].Name;
                    treeAll.Expanded = true;
                    treeAll.IsLeaf = false;
                    treeAll.children = GetChild(treeAll, fp);
                   
                }
            }

            listTreeAll.Add(treeAll);


            return new GetRoleForEditOutput
            {
                Role = roleEditDto,//角色信息
                Permissions = fp,//所有权限
                GrantedPermissionNames = grantedPermissions.Select(p => p.Name).ToList(),//选中 展开节点
                GetRoleNodes = listTreeAll
            };
        }

        private List<RoleNodes> GetChild(RoleNodes nodes , List<FlatPermissionDto> fp)
        {
          
            List<RoleNodes> child = new List<RoleNodes>();
            List<FlatPermissionDto> clist = fp.Where(c => c.ParentName == nodes.Key).ToList();
            for (int i = 0; i < clist.Count; i++)
            {
                List<FlatPermissionDto> clist1 = fp.Where(c => c.ParentName == clist[i].Name).ToList();
                RoleNodes n = new RoleNodes();
                n.Title = clist[i].DisplayName;
                n.Key = clist[i].Name;
                n.IsLeaf = clist1.Count > 0 ? false : true;
                n.Expanded = true;
                child.Add(n);
                if (clist1.Count > 0)
                {
                    n.children = GetChild(n, fp);
                }
            }
            return child;
        }

        public async Task CreateOrUpdateRole(CreateOrUpdateRoleInput input)
        {
            if (input.Role.Id>0)
            {
                await UpdateRoleAsync(input);
            }
            else
            {
                await CreateRoleAsync(input);
            }
        }

        protected virtual async Task UpdateRoleAsync(CreateOrUpdateRoleInput input)
        {
       
            var role = await _roleManager.GetRoleByIdAsync(input.Role.Id);
            role.DisplayName = input.Role.DisplayName;
            role.Name= input.Role.Name;
            role.Description = input.Role.Description;
            await UpdateGrantedPermissionsAsync(role, input.GrantedPermissionNames);
        }

        protected virtual async Task CreateRoleAsync(CreateOrUpdateRoleInput input)
        {
            var role = new Role(AbpSession.TenantId, input.Role.Name , input.Role.DisplayName);
            role.Description = input.Role.Description;
            CheckErrors(await _roleManager.CreateAsync(role));
            await CurrentUnitOfWork.SaveChangesAsync(); //It's done to get Id of the role.
            await UpdateGrantedPermissionsAsync(role, input.GrantedPermissionNames);
        }

        private async Task UpdateGrantedPermissionsAsync(Role role, List<string> grantedPermissionNames)
        {
            var grantedPermissions = PermissionManager.GetPermissionsFromNamesByValidating(grantedPermissionNames);
            await _roleManager.SetGrantedPermissionsAsync(role, grantedPermissions);
        }
    }
}


